import React, {PureComponent, PropTypes} from 'react';

import styles from './style.scss';

import jRoll from 'jroll';
import "jroll-pulldown";

import LoadImage from './loading.gif';
import Arrow from './arrow.png';
import Success from './success.png';

class ScrollView extends PureComponent {

    static propTypes = {
        onEndReachedThreshold:PropTypes.number,
        onEndReached:PropTypes.func,
        onRefresh:PropTypes.func
    };

    static defaultProps = {
        onEndReachedThreshold:100,
        onEndReached:()=>{},
        onRefresh:()=>{}
    };

    scrollX = 0;
    scrollY = 0;

    isOnEndReached = false;

    nameConfig = {
       x:[`right`,`left`],
       y:[`down`,`up`]
    };

    eventTypes = [
        `scrollStart`,
        `scroll`,
        `scrollEnd`,
        `touchEnd`
    ];

    abs = num => Math.abs(num);

    bind = f => f.bind(this.jRoll);

    getCurrentSize = el => el.getBoundingClientRect();

    getImageStr = icon=>`<img class="load_image" src="${icon}"/>`;

    componentDidMount() {
        this.init();
    }

    init() {
        this.jRoll = new jRoll(this.element, {
            scrollBarY: true,
            scrollBarFade: true
        });
        this.pullDown();
        this.bindEvent();
    }

    pullDown(){
        const { pulldown } = this.jRoll;
        this.bind(pulldown)({
            textLoading:"更新中...",
            spinning:false,
            iconArrow:this.getImageStr(Arrow),
            iconLoading:this.getImageStr(LoadImage),
            iconFinish:this.getImageStr(Success),
            refresh: this.props.onRefresh
        });
    }

    bindEvent() {
        const { on } = this.jRoll;
        this.eventTypes.forEach( type => (
            this.bind(on)( type , e => this.handel(type))
        ));
    }

    handel( eventType ) {

        const { x , y } = this.jRoll;

        this.shouldRefresh();

        switch ( eventType ){
            case `scrollStart`:
                this.scrollX = x;
                this.scrollY = y;
                break;
            case `scroll`:
                this.handelOut();
                break;
            case `scrollEnd`:
                this.handelOut();
                break;
        }
    }

    handelOut () {
        const result = this.computed();

        const {
            onEndReached ,
            onEndReachedThreshold
        } = this.props;

        const { y , maxScrollY } = this.jRoll;

        if( result.y === false) return false;

        const diffY = this.abs(maxScrollY) - this.abs(y);

        if( diffY <= onEndReachedThreshold ) {
            if( !this.isOnEndReached ) {
                this.isOnEndReached = true;
                onEndReached();
            }
            return false;
        }
        this.isOnEndReached = false;
    }


    computed() {
        const { s } = this.jRoll;

        let compute = { x:false, y:false };

        [`x`,`y`].some( key => {

            const useKey = key.toLocaleUpperCase();

            if(s !== `scroll${useKey}`) return false;

            const names = this.nameConfig[key];

            const range = this.jRoll[key],
                  maxRange = this.jRoll[`maxScroll${useKey}`];

            //超出边界
            if( range >= 0 || this.abs(range) >= this.abs(maxRange) ){
                return false
            }

            const diffRange = range - this[`scroll${useKey}`];

            if( diffRange !== 0 ) {
                compute[key] = diffRange > 0 ? names[0]:names[1];
            }

            if(this.abs(diffRange) >= 6) {
                this[`scroll${useKey}`] = range;
            }

            return true;
        });

        return compute;
    }

    rectChange() {
        const  types = [`scroller`,`wrapper`];
        return types.some( type => {
            const element   = this.jRoll[type];
            const oldWidth  = ~~this.jRoll[`${type}Width`],
                  oldHeight = ~~this.jRoll[`${type}Height`];
            const { width , height } = this.getCurrentSize(element);
            return (~~width !== oldWidth || ~~height !== oldHeight);
        });
    }

    shouldRefresh() {
        const isRefresh = this.rectChange();
        if(isRefresh) {
           this.refresh();
        }
    }

    refresh (){
        const { refresh } = this.jRoll;
        this.bind(refresh)();
    }

    componentWillUnmount() {
        const {destroy} = this.jRoll;
        this.bind(destroy)();
    }

    render() {
        const {children} = this.props;
        return (
            <div className={styles.scroll_view} ref={el => this.element = el}>
                <div className={styles.scroll_view_inner}>
                    {children}
                </div>
            </div>
        )

    }

}

export default ScrollView;
